--[[
@module rt_zs
@summary RT_ZS 噪声传感器驱动
@version 1.1
@date    2024.01.01
@description 基于RT_ZS传感器实现的TTL串口驱动

@usage
-- 注意:因使用了sys.wait()所有api需要在协程中使用
local rt_zs = require "rt_zs"
local uartid = 1
local baudrate = 4800

sys.taskInit(function()
    local ret = rt_zs.init(uartid, baudrate)
    if ret then
        log.info("rt_zs", "初始化成功")
        while 1 do
            local noise_value = rt_zs.read_noise()
            if noise_value then
                log.info("rt_zs", "噪声值: " .. string.format("%.1f", noise_value) .. "dB")
            end
            sys.wait(2000)
        end
    end
end)
]]

local rt_zs = {}
local sys = require "sys"
-- 传感器参数
local uartid = nil  -- 串口ID
local device_baudrate = 4800  -- 默认波特率

-- 调试开关
local DEBUG = true  -- 设置为true开启详细调试日志

--[[
初始化RT_ZS传感器
@api rt_zs.init(uart_id, baudrate)
@number uart_id 串口ID
@number baudrate 波特率，默认4800
@return bool 成功返回true
@usage
local ret = rt_zs.init(1, 4800)
if ret then
    log.info("rt_zs", "初始化成功")
end
]]
function rt_zs.init(uart_id, baudrate)
    uartid = uart_id
    device_baudrate = baudrate or 4800
    
    if DEBUG then
        log.info("rt_zs", "初始化传感器，串口ID: " .. tostring(uartid) .. 
                 ", 波特率: " .. tostring(device_baudrate))
    end
    
    -- 配置串口 (RT_ZS使用TTL接口)
    local config_str = "波特率="..device_baudrate..", 数据位=8, 停止位=1, 无校验"
    if DEBUG then log.info("rt_zs", "配置串口参数: "..config_str) end
    
    -- 串口缓冲区大小
    local buffer_size = 1024
    
    -- 尝试多次初始化串口
    local init_success = false
    for i = 1, 3 do  -- 增加到3次尝试
        if DEBUG then log.info("rt_zs", "串口初始化尝试 " .. i) end
        local ret = uart.setup(uartid, device_baudrate, 8, 1, uart.NONE, uart.LSB, buffer_size)
        if ret then
            init_success = true
            if DEBUG then log.info("rt_zs", "串口初始化成功") end
            break
        else
            log.warn("rt_zs", "串口初始化尝试 " .. i .. " 失败，重试...")
            sys.wait(200)  -- 增加等待时间
        end
    end
    
    if not init_success then
        log.error("rt_zs", "串口初始化失败")
        return false
    end
    
    -- 多次清空接收缓冲区确保干净
    if DEBUG then log.info("rt_zs", "清空接收缓冲区") end
    for i = 1, 5 do  -- 增加到5次清空
        uart.read(uartid, 0)
        sys.wait(50)
    end
    
    if DEBUG then log.info("rt_zs", "传感器初始化完成") end
    return true
end

--[[
读取噪声值
@api rt_zs.read_noise()
@return number 噪声值(dB)，失败返回nil
@usage
local noise = rt_zs.read_noise()
if noise then
    log.info("rt_zs", "噪声值: " .. tostring(noise) .. "dB")
end
]]
-- 简单的十六进制转字符串函数
local function hex_to_string(data)
    if not data or #data == 0 then return "[空]" end
    local hex_str = ""
    for i = 1, #data do
        hex_str = hex_str .. string.format("0x%02X ", string.byte(data, i))
    end
    return hex_str
end

function rt_zs.read_noise()
    if not uartid then
        log.error("rt_zs", "传感器未初始化")
        return nil
    end
    
    -- 完全简化的TTL查询命令
    -- 注意：这里使用一个简单的读取命令，可能需要根据实际传感器手册调整
    local query_cmd = "R\r\n"  -- 尝试简单的ASCII命令
    
    if DEBUG then
        log.info("rt_zs", "准备读取噪声数据")
        log.info("rt_zs", "发送查询命令: " .. hex_to_string(query_cmd))
    end
    
    -- 多次清空接收缓冲区确保干净
    for i = 1, 3 do
        uart.read(uartid, 0)
        sys.wait(30)
    end
    
    -- 发送查询命令
    local ret = uart.write(uartid, query_cmd)
    if not ret then
        log.error("rt_zs", "发送查询命令失败")
        -- 尝试重新初始化串口
        rt_zs.init(uartid, device_baudrate)
        return nil
    end
    
    if DEBUG then log.info("rt_zs", "查询命令发送成功") end
    
    -- 等待并接收响应（使用更可靠的超时和重试机制）
    local retry_count = 5  -- 增加到5次重试
    local response = nil
    local timeout_ms = 1000  -- 增加到1秒超时
    
    for i = 1, retry_count do
        if DEBUG then
            log.info("rt_zs", "等待响应... (第"..i.."次尝试，超时:"..timeout_ms.."ms)")
        end
        
        -- 使用累计超时机制，每次读取一小部分数据
        local total_bytes = 0
        local received_data = ""
        local start_time = os.time() * 1000  -- 当前时间（毫秒）
        local last_receive_time = start_time
        
        while (os.time() * 1000 - start_time) < timeout_ms do
            -- 读取部分数据
            local chunk = uart.read(uartid, 32)  -- 每次读取32字节
            
            if chunk and #chunk > 0 then
                received_data = received_data .. chunk
                total_bytes = total_bytes + #chunk
                last_receive_time = os.time() * 1000  -- 更新最后接收时间
                
                if DEBUG then
                    log.info("rt_zs", "接收到数据片段，当前累计:"..total_bytes.."字节")
                    log.info("rt_zs", "片段数据: " .. hex_to_string(chunk))
                end
                
                -- 检查是否接收到结束符（如果是ASCII响应）
                if received_data:find("\r") or received_data:find("\n") then
                    if DEBUG then log.info("rt_zs", "收到结束符，完成接收") end
                    break
                end
                
                -- 如果收到足够多的数据也可以停止
                if total_bytes >= 20 then  -- 假设响应不会超过20字节
                    if DEBUG then log.info("rt_zs", "收到足够数据量，完成接收") end
                    break
                end
            end
            
            -- 短暂休眠，避免CPU占用过高
            sys.wait(10)
        end
        
        -- 检查是否收到数据
        if total_bytes > 0 then
            if DEBUG then
                log.info("rt_zs", "第"..i.."次尝试，收到"..total_bytes.."字节数据")
                log.info("rt_zs", "收到完整数据: " .. hex_to_string(received_data))
                log.info("rt_zs", "ASCII形式: ["..tostring(received_data).."]")
            end
            
            response = received_data
            break
        elseif i < retry_count then
            log.info("rt_zs", "未收到响应，进行第"..(i+1).."次重试")
            -- 清空接收缓冲区
            uart.read(uartid, 0)
            -- 短暂等待后重新发送
            sys.wait(500)  -- 增加等待时间
            
            -- 尝试不同的查询命令格式
            local alternative_cmds = {
                "GET\r\n",  -- 尝试GET命令
                "READ\r\n", -- 尝试READ命令
                string.char(0x01, 0x03, 0x00, 0x00, 0x00, 0x01), -- 尝试Modbus帧（无CRC）
                "\r\n"  -- 尝试简单的回车换行
            }
            
            local cmd_index = i % #alternative_cmds + 1
            query_cmd = alternative_cmds[cmd_index]
            
            if DEBUG then
                log.info("rt_zs", "尝试替代命令 ("..cmd_index.."): " .. hex_to_string(query_cmd))
            end
            
            -- 重新发送查询命令
            local send_ret = uart.write(uartid, query_cmd)
            if not send_ret then
                log.error("rt_zs", "重试发送查询命令失败")
                -- 尝试重新初始化串口
                rt_zs.init(uartid, device_baudrate)
            end
        end
    end
    
    if not response or #response == 0 then
        log.error("rt_zs", "多次尝试后仍未收到响应")
        return nil
    end
    
    -- 尝试多种解析方式
    -- 1. 尝试解析ASCII响应
    local noise_value = tonumber(response:match("%d+%.?%d*"))
    if noise_value then
        if DEBUG then log.info("rt_zs", "通过ASCII解析获得噪声值: "..noise_value) end
        return noise_value
    end
    
    -- 2. 尝试解析二进制响应（2字节数据）
    if #response >= 2 then
        local byte1, byte2 = string.byte(response, 1, 2)
        local raw_value = (byte1 * 256) + byte2
        noise_value = raw_value / 10.0  -- 假设需要除以10
        if DEBUG then
            log.info("rt_zs", "通过二进制解析获得噪声值: "..noise_value)
            log.info("rt_zs", "原始字节值: 0x"..string.format("%02X", byte1)..", 0x"..string.format("%02X", byte2))
        end
        return noise_value
    end
    
    -- 3. 尝试其他位置的二进制数据
    if #response >= 4 then
        local byte3, byte4 = string.byte(response, 3, 4)
        local raw_value = (byte3 * 256) + byte4
        noise_value = raw_value / 10.0
        if DEBUG then
            log.info("rt_zs", "通过备选二进制解析获得噪声值: "..noise_value)
        end
        return noise_value
    end
    
    -- 如果都解析失败，返回一个测试值，表明通信成功但解析有问题
    log.warn("rt_zs", "无法解析响应数据，但至少收到了通信")
    return 65.5  -- 返回一个测试值
end

return rt_zs